package com.gzx.spring.apis.utils;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.google.gson.Gson;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class YuyaoUtil {

	private String appId;
	private String appSecret;

	private String apiUrl;

	private static final String PROVIDER = "BC";
	private static final String ALGORITHM_NAME = "SM4/ECB/PKCS7Padding";

	public YuyaoUtil appId(String appId) {
		this.appId = appId;
		return this;
	}

	public YuyaoUtil appSecret(String appSecret) {
		this.appSecret = appSecret;
		return this;
	}

	public YuyaoUtil apiUrl(String apiUrl) {
		this.apiUrl = apiUrl;
		return this;
	}

	private String generateMD5Signature(Map<String, String> params) {
		try {
			// 参数排序
			SortedMap<String, String> sortedParams = new TreeMap<>(Comparator.naturalOrder());
			for (Map.Entry<String, String> entry : params.entrySet()) {
				sortedParams.put(entry.getKey(), entry.getValue() == null ? "" : entry.getValue());
			}

			// 拼接排序后的参数（不包含sign本身）
			StringBuilder paramString = new StringBuilder();
			for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
				paramString.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
			}

			// 移除最后一个"&"并添加盐值
			paramString.deleteCharAt(paramString.length() - 1);
			paramString.append(appSecret);

			// System.out.println("待签名字符串：" + paramString);

			// 转换为UTF-8编码并计算MD5摘要
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] hash = md.digest(paramString.toString().getBytes(StandardCharsets.UTF_8));

			// 转换为32位字符串
			return String.format("%032x", new BigInteger(1, hash));
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException("MD5 Algorithm not available!", e);
		}
	}

	private String getEncryptKey() throws NoSuchAlgorithmException {
		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] hash = md.digest(appSecret.getBytes(StandardCharsets.UTF_8));
		String md5Result = String.format("%032x", new BigInteger(1, hash)).toUpperCase();
		return md5Result.substring(16, 32);
	}

	private String sm4Encrypt(String content) {
		Security.addProvider(new BouncyCastleProvider());
		try {
			byte[] keyBytes = getEncryptKey().getBytes(StandardCharsets.US_ASCII);
			SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "SM4");

			byte[] plaintext = content.getBytes(StandardCharsets.UTF_8);
			byte[] ciphertext;
			Cipher cipher;

			try {
				cipher = Cipher.getInstance(ALGORITHM_NAME, PROVIDER);
			} catch (NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException e) {
				throw new RuntimeException(e);
			}

			try {
				cipher.init(Cipher.ENCRYPT_MODE, keySpec);
				ciphertext = cipher.doFinal(plaintext);
				return bytesToHex(ciphertext).toUpperCase();
			} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException e) {
				throw new RuntimeException(e);
			}
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}

	private String getMD5String(String content) {
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
		byte[] hash = md.digest(appSecret.getBytes(StandardCharsets.UTF_8));
		return String.format("%032x", new BigInteger(1, hash)).toUpperCase();
	}

	private String bytesToHex(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (byte b : bytes) {
			sb.append(String.format("%02x", b));
		}
		return sb.toString();
	}
	private String exec(String url,Map<String, String> params) throws IOException {
		params.put("appId", appId);
		params.put("ts", String.valueOf(System.currentTimeMillis() / 1000));// 10位时间戳
		params.put("version", "V1");
		params.put("requestId", getMD5String("010449fa-aa1d-4d50-b068-bd34f233"));// 32位字符串：仅字母和数字组成
		String signature = generateMD5Signature(params);
		params.put("sign", signature);

		Gson gson = new Gson();
		String jsonStr = gson.toJson(params);
		// System.out.println("请求数据：" + jsonStr);

		OkHttpClient client = new OkHttpClient();
		MediaType JSON = MediaType.parse("application/json; charset=utf-8");
		RequestBody body = RequestBody.create(JSON, jsonStr);
		Request request = new Request.Builder().url(apiUrl + url).post(body).build();
		Response response = client.newCall(request).execute();
		return response.body().string();
	}
	//融安云网分：RA营销分进阶版
	public String ra_high_score(String name, String id, String phone) throws Exception {
		String nameEncrypt = sm4Encrypt(name);
		String idNoEncrypt = sm4Encrypt(id);
		String phoneEncrypt = sm4Encrypt(phone);

		Map<String, String> params = new HashMap<>();
		params.put("name", nameEncrypt);// sm4加密后的数据
		params.put("idNo", idNoEncrypt);// sm4加密后的数据
		params.put("phone", phoneEncrypt);// sm4加密后的数据
		
		return exec("/discern/ra_high_score",params);
	}

	// 借贷意向验证：BRDT
	public String brdt_score(String name, String id, String phone) throws Exception {
		String nameEncrypt = sm4Encrypt(name);
		String idNoEncrypt = sm4Encrypt(id);
		String phoneEncrypt = sm4Encrypt(phone);

		Map<String, String> params = new HashMap<>();
		params.put("id", idNoEncrypt);// sm4加密后的数据
		params.put("cell", phoneEncrypt);// sm4加密后的数据
		params.put("name", nameEncrypt);// sm4加密后的数据

		return exec("/discern/brdt_score",params);
	}
	
	// 申请反欺诈：FQZ 营销分
	public String gatewayC108139(String phone) throws Exception {
		String phoneEncrypt = sm4Encrypt(phone);

		Map<String, String> params = new HashMap<>();
		params.put("productId", "C108139");
        params.put("phone", phoneEncrypt);// sm4加密后的数据

		return exec("/unifiedorder/gateway",params);
	}
	
	//信用司南：XYSN营销分
	public String gatewayC108144(String name, String id, String phone) throws Exception {
		String nameEncrypt = sm4Encrypt(name);
		String idNoEncrypt = sm4Encrypt(id);
		String phoneEncrypt = sm4Encrypt(phone);

		Map<String, String> params = new HashMap<>();
		params.put("productId", "C108144");
        params.put("idNo", idNoEncrypt);// sm4加密后的数据
        params.put("phone", phoneEncrypt);// sm4加密后的数据
        params.put("name", nameEncrypt);// sm4加密后的数据

		return exec("/unifiedorder/gateway",params);
	}
	
	//在网时长：ZWSC营销分
	public String mobileOnLineVerify(String phone) throws Exception {
		String phoneEncrypt = sm4Encrypt(phone);

		Map<String, String> params = new HashMap<>();
        params.put("phone", phoneEncrypt);// sm4加密后的数据

		return exec("/verify/mobileOnLineVerify",params);
	}
	
	//在网状态：ZWZT营销分
	public String mobilestatus(String phone) throws Exception {
		String phoneEncrypt = sm4Encrypt(phone);

		Map<String, String> params = new HashMap<>();
        params.put("phone", phoneEncrypt);// sm4加密后的数据
		return exec("/verify/mobilestatus",params);
	}
	
	//特殊名单验证：BRMD
	public String gatewayC108143(String name, String id, String phone) throws Exception {
		String nameEncrypt = sm4Encrypt(name);
		String idNoEncrypt = sm4Encrypt(id);
		String phoneEncrypt = sm4Encrypt(phone);

		Map<String, String> params = new HashMap<>();
		params.put("productId", "C108143");
        params.put("idNo", idNoEncrypt);// sm4加密后的数据
        params.put("phone", phoneEncrypt);// sm4加密后的数据
        params.put("name", nameEncrypt);// sm4加密后的数据
        
		return exec("/unifiedorder/gateway",params);
	}
	
	//司法个人
	public String personal(String name, String id, String authDate) throws Exception {
		String nameEncrypt = sm4Encrypt(name);
		String idNoEncrypt = sm4Encrypt(id);

		Map<String, String> params = new HashMap<>();
        params.put("idNo", idNoEncrypt);// sm4加密后的数据
        params.put("name", nameEncrypt);// sm4加密后的数据
        params.put("authDate", authDate);
        
		return exec("/uranus/personal",params);
	}
}
